home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / program / swagg_m.zip / MISC.SWG / 0004_FLIPLAY.PAS.pas < prev    next >
Pascal/Delphi Source File  |  1993-05-28  |  33KB  |  686 lines

  1. {$G+}
  2.  
  3. Program FliPlayer;
  4.  
  5. {  v1.1 made by Thaco   }
  6. { (c) EPOS, August 1992 }
  7.  
  8.  
  9. Const
  10.   CLOCK_HZ              =4608;                   { Frequency of clock }
  11.   MONItoR_HZ            =70;                     { Frequency of monitor }
  12.   CLOCK_SCALE           =CLOCK_HZ div MONItoR_HZ;
  13.  
  14.   BUFFERSIZE            =$FFFE;                  { Size of the framebuffer, must be an even number }
  15.   CDATA                 =$040;                   { Port number of timer 0 }
  16.   CMODE                 =$043;                   { Port number of timers control Word }
  17.   CO80                  =$3;                     { Number For standard Text mode }
  18.   KEYBOARD              =28;                     { Numbers returned by PorT[$64] indicating what hardware caused inT 09/the - }
  19.   MOUSE                 =60;                     { - number on PorT[$60] }
  20.   MCGA                  =$13;                    { Number For MCGA mode }
  21.   MCGACheck:Boolean     =True;                   { Variable For MCGA checking }
  22.   UseXMS:Boolean        =True;                   { Variable For XMS usage }
  23.   XMSError:Byte         =0;                      { Variable indicating the errornumber returned from the last XMS operation }
  24.  
  25. Type
  26.   EMMStructure          =Record
  27.                            BytestoMoveLo,              { Low Word of Bytes to move. NB: Must be even! }
  28.                            BytestoMoveHi,              { High Word of Bytes to move }
  29.                            SourceHandle,               { Handle number of source (SH=0 => conventional memory) }
  30.                            SourceoffsetLo,             { Low Word of source offset, or ofS if SH=0 }
  31.                            SourceoffsetHi,             { High Word of source offset, or SEG if SH=0 }
  32.                            DestinationHandle,          { Handle number of destination (DH=0 => conventional memory) }
  33.                            DestinationoffsetLo,        { Low Word of destination offset, or ofS if DH=0 }
  34.                            DestinationoffsetHi  :Word; { High Word of destination offset, or SEG if DH=0 }
  35.                          end;
  36.   HeaderType            =Array[0..128] of Byte;  { A bufferType used to read all kinds of headers }
  37.  
  38.  
  39. Var
  40.   Key,                                           { Variable used to check if a key has been pressed }
  41.   OldKey                :Byte;                   { Variable used to check if a key has been pressed }
  42.   XMSRecord             :EMMStructure;           { Variable For passing values to the XMS routine }
  43.   InputFile             :File;                   { Variable For the incomming .FLI File }
  44.   Header                :HeaderType;             { Buffer used to read all kinds of headers }
  45.   Counter,                                       { General purpose counter }
  46.   Speed                 :Integer;                { Timedifference in video tics from one frame to the next }
  47.   FileCounter,                                   { Variable telling the point to read from in the File stored in XMS }
  48.   FileSize,                                      { Size of the .FLI-File }
  49.   FrameSize,                                     { Variable indicating the datasize of current frame }
  50.   NextTime,                                      { Variable saying when it is time to move on to the next frame }
  51.   TimeCounter,                                   { Holding the current time in video tics }
  52.   SecondPos             :LongInt;                { Number of Bytes to skip from the start of the .FLI File when starting - }
  53.                                                  { - from the beginning again }
  54.   Buffer,                                        { Pointer to the Framebuffer }
  55.   XMSEntryPoint         :Pointer;                { Entry point of the XMS routine in memory }
  56.   SpeedString           :String[2];              { String used to parse the -sNN command }
  57.   FileName              :String[13];             { String holding the name of the .FLI-File }
  58.   BufferHandle,                                  { Handle number returned from the XMS routine }
  59.   BytesRead,                                     { Variable telling the numbers of Bytes read from the .FLI File }
  60.   FrameNumber,                                   { Number of the current frame }
  61.   Frames,                                        { total number of frames }
  62.   Chunks                :Word;                   { total number of chunks in a frame }
  63.  
  64.  
  65. Function UpCaseString(Streng:String):String;
  66. { takes a String and convert all letters to upperCase }
  67. Var
  68.   DummyString           :String;
  69.   Counter               :Integer;
  70. begin
  71.   DummyString:='';
  72.   For Counter:=1 to Length(Streng) do
  73.     DummyString:=DummyString+UpCase(Streng[Counter]);
  74.   UpCaseString:=DummyString;
  75. end;
  76.  
  77.  
  78. Procedure InitMode(Mode:Word); Assembler;
  79. { Uses BIOS interrupts to set a videomode }
  80. Asm
  81.   mov  ax,Mode
  82.   int  10h
  83. end;
  84.  
  85.  
  86. Function ModeSupport(Mode:Word):Boolean; Assembler;
  87. { Uses BIOS interrupts to check if a videomode is supported }
  88. Label Exit, Last_Modes, No_Support, Supported;
  89. Var
  90.   DisplayInfo           :Array[1..64] of Byte;   { Array For storing Functionality/state inFormation }
  91. Asm
  92.   push es
  93.  
  94.   mov  ah,1Bh                                    { the Functionality/state inFormation request at int 10h }
  95.   mov  bx,0                                      { 0 = return Functionality/state inFormation }
  96.   push ds                                        { push DS on the stack and pop it into ES so ES:DI could be used to - }
  97.   pop  es                                        { - address DisplayInfo, as demanded of the interrupt Function }
  98.   mov  di,offset DisplayInfo
  99.   int  10h
  100.  
  101.   les  di,[dWord ptr es:di]                      { The first dWord in the buffer For state inFormation is the address - }
  102.                                                  { - of static funtionality table }
  103.   mov  cx,Mode                                   { Can only check For the 0h-13h modes }
  104.   cmp  cx,13h
  105.   ja   No_Support                                { Return 'no support' For modes > 13h }
  106.  
  107.   mov  ax,1                                      { Shift the right Byte the right - }
  108.                                                  { - times and test For the right - }
  109.   cmp  cx,10h                                    { - bit For knowing if the       - }
  110.   jae  Last_Modes                                { - videomode is supported       - }
  111.                                                  { -                                }
  112.   shl  ax,cl                                     { -                                }
  113.   test ax,[Word ptr es:di+0]                     { -                                }
  114.   jz   No_Support                                { -                                }
  115.   jmp  Supported                                 { -                                }
  116.                                                  { -                                }
  117. Last_Modes:                                      { -                                }
  118.   sub  cx,10h                                    { -                                }
  119.   shl  ax,cl                                     { -                                }
  120.   test al,[Byte ptr es:di+2]                     { -                                }
  121.   jz   No_Support                                { -                                }
  122.  
  123. Supported:
  124.   mov  al,1                                      { AL=1 makes the Function return True }
  125.   jmp  Exit
  126.  
  127. No_Support:
  128.   mov  al,0                                      { AL=0 makes the Function return True }
  129.  
  130. Exit:
  131.   pop  es
  132. end;
  133.  
  134.  
  135. Function NoXMS:Boolean; Assembler;
  136. { checks out if there is a XMS driver installed, and in Case it initialize the
  137.   XMSEntryPoint Variable }
  138. Label JumpOver;
  139. Asm
  140.   push es
  141.  
  142.   mov  ax,4300h                                  { AX = 4300h => inSTALLATION CHECK }
  143.   int  2Fh                                       { use int 2Fh Extended MEMorY SPECifICATION (XMS) }
  144.   mov  bl,1                                      { use BL as a flag to indicate success }
  145.   cmp  al,80h                                    { is a XMS driver installed? }
  146.   jne  JumpOver
  147.   mov  ax,4310h                                  { AX = 4310h => GET DRIVER ADDRESS }
  148.   int  2Fh
  149.   mov  [Word ptr XMSEntryPoint+0],BX             { initialize low Word of XMSEntryPoint }
  150.   mov  [Word ptr XMSEntryPoint+2],ES             { initialize high Word of XMSEntryPoint }
  151.   mov  bl,0                                      { indicate success }
  152. JumpOver:
  153.   mov  al,bl                                     { make the Function return True (AH=1) or False (AH=0) }
  154.  
  155.   pop  es
  156. end;
  157.  
  158.  
  159. Function XMSMaxAvail:Word; Assembler;
  160. { returns size of largest contiguous block of XMS in kilo (1024) Bytes }
  161. Label JumpOver;
  162. Asm
  163.   mov  ah,08h                                    { 'Query free Extended memory' Function }
  164.   mov  XMSError,0                                { clear error Variable }
  165.   call [dWord ptr XMSEntryPoint]
  166.   or   ax,ax                                     { check For error }
  167.   jnz  JumpOver
  168.   mov  XMSError,bl                               { errornumber stored in BL }
  169. JumpOver:                                        { AX=largest contiguous block of XMS }
  170. end;
  171.  
  172.  
  173. Function XMSGetMem(SizeInKB:Word):Word; Assembler;
  174. { allocates specified numbers of kilo (1024) Bytes of XMS and return a handle
  175.   to this XMS block }
  176. Label JumpOver;
  177. Asm
  178.   mov  ah,09h                                    { 'Allocate Extended memory block' Function }
  179.   mov  dx,SizeInKB                               { number of KB requested }
  180.   mov  XMSError,0                                { clear error Variable }
  181.   call [dWord ptr XMSEntryPoint]
  182.   or   ax,ax                                     { check For error }
  183.   jnz  JumpOver
  184.   mov  XMSError,bl                               { errornumber stored in BL }
  185. JumpOver:
  186.   mov  ax,dx                                     { return handle number to XMS block }
  187. end;
  188.  
  189.  
  190. Procedure XMSFreeMem(Handle:Word); Assembler;
  191. Label JumpOver;
  192. Asm
  193.   mov  ah,0Ah                                    { 'Free Extended memory block' Function }
  194.   mov  dx,Handle                                 { XMS's handle number to free }
  195.   mov  XMSError,0                                { clear error Variable }
  196.   call [dWord ptr XMSEntryPoint]
  197.   or   ax,ax                                     { check For error }
  198.   jnz  JumpOver
  199.   mov  XMSError,bl                               { errornumber stored in BL }
  200. JumpOver:
  201. end;
  202.  
  203.  
  204. Procedure XMSMove(Var EMMParamBlock:EMMStructure); Assembler;
  205. Label JumpOver;
  206. Asm
  207.   push ds
  208.   push es
  209.   push ds
  210.   pop  es
  211.   mov  ah,0Bh                                    { 'Move Extended memory block' Function }
  212.   mov  XMSError,0                                { clear error Variable }
  213.   lds  si,EMMParamBlock                          { DS:SI -> data to pass to the XMS routine }
  214.   call [dWord ptr es:XMSEntryPoint]
  215.   or   ax,ax                                     { check For error }
  216.   jnz  JumpOver
  217.   mov  XMSError,bl                               { errornumber stored in BL }
  218. JumpOver:
  219.   pop  es
  220.   pop  ds
  221. end;
  222.  
  223.  
  224. Procedure ExitDuetoXMSError;
  225. begin
  226.   InitMode(CO80);
  227.   WriteLn('ERRor! XMS routine has reported error ',XMSError);
  228.   XMSFreeMem(BufferHandle);
  229.   Halt(0);
  230. end;
  231.  
  232.  
  233. Procedure GetBlock(Var Buffer; Size:Word);
  234. { reads a specified numbers of data from a diskFile or XMS into a buffer }
  235. Var
  236.   XMSRecord             :EMMStructure;
  237.   NumberofBytes         :Word;
  238. begin
  239.   if UseXMS then
  240.   begin
  241.     NumberofBytes:=Size;
  242.     if Size MOD 2=1 then
  243.       Inc(NumberofBytes);  { one must allways ask For a EQUAL number of Bytes }
  244.     With XMSRecord do
  245.     begin
  246.       BytestoMoveLo      :=NumberofBytes;
  247.       BytestoMoveHi      :=0;
  248.       SourceHandle       :=BufferHandle;
  249.       SourceoffsetLo     :=FileCounter MOD 65536;
  250.       SourceoffsetHi     :=FileCounter div 65536;
  251.       DestinationHandle  :=0;
  252.       DestinationoffsetLo:=ofs(Buffer);
  253.       DestinationoffsetHi:=Seg(Buffer);
  254.     end;
  255.     XMSMove(XMSRecord);
  256.     if XMSError<>0 then
  257.       ExitDuetoXMSError;
  258.     Inc(FileCounter,Size);
  259.   end
  260.   else
  261.     BlockRead(InputFile,Buffer,Size);
  262. end;
  263.  
  264.  
  265. Procedure InitClock; Assembler; {Taken from the FLILIB source}
  266. Asm
  267.   mov  al,00110100b                                 { put it into liNear count instead of divide by 2 }
  268.   out  CMODE,al
  269.   xor  al,al
  270.   out  CDATA,al
  271.   out  CDATA,al
  272. end;
  273.  
  274.  
  275. Function GetClock:LongInt; Assembler; {Taken from the FLILIB source}
  276. { this routine returns a clock With occassional spikes where time
  277.   will look like its running backwards 1/18th of a second.  The resolution
  278.   of the clock is 1/(18*256) = 1/4608 second.  66 ticks of this clock
  279.   are supposed to be equal to a monitor 1/70 second tick.}
  280. Asm
  281.   mov  ah,0                                         { get tick count from Dos and use For hi 3 Bytes }
  282.   int  01ah                                         { lo order count in DX, hi order in CX }
  283.   mov  ah,dl
  284.   mov  dl,dh
  285.   mov  dh,cl
  286.  
  287.   mov  al,0                                         { read lo Byte straight from timer chip }
  288.   out  CMODE,al                                         { latch count }
  289.   mov  al,1
  290.   out  CMODE,al                                         { set up to read count }
  291.   in   al,CDATA                                         { read in lo Byte (and discard) }
  292.   in   al,CDATA                                         { hi Byte into al }
  293.   neg  al                                         { make it so counting up instead of down }
  294. end;
  295.  
  296.  
  297. Procedure TreatFrame(Buffer:Pointer;Chunks:Word); Assembler;
  298. { this is the 'workhorse' routine that takes a frame and put it on the screen }
  299. { chunk by chunk }
  300. Label
  301.   Color_Loop, Copy_Bytes, Copy_Bytes2, Exit, Fli_Black, Fli_Brun, Fli_Color,
  302.   Fli_Copy, Fli_Lc, Fli_Loop, Jump_Over, Line_Loop, Line_Loop2, Next_Line,
  303.   Next_Line2, Pack_Loop, Pack_Loop2;
  304. Asm
  305.   cli                                            { disable interrupts }
  306.   push ds
  307.   push es                                        
  308.   lds  si,Buffer                                 { let DS:SI point at the frame to be drawn }
  309.  
  310. Fli_Loop:                                        { main loop that goes through all the chunks in a frame }
  311.   cmp  Chunks,0                                  { are there any more chunks to draw? }
  312.   je   Exit
  313.   dec  Chunks                                    { decrement Chunks For the chunk to process now }
  314.  
  315.   mov  ax,[Word ptr ds:si+4]                     { let AX have the ChunkType }
  316.   add  si,6                                      { skip the ChunkHeader }
  317.  
  318.   cmp  ax,0Bh                                    { is it a FLI_COLor chunk? }
  319.   je   Fli_Color
  320.   cmp  ax,0Ch                                    { is it a FLI_LC chunk? }
  321.   je   Fli_Lc
  322.   cmp  ax,0Dh                                    { is it a FLI_BLACK chunk? }
  323.   je   Fli_Black
  324.   cmp  ax,0Fh                                    { is it a FLI_BRUN chunk? }
  325.   je   Fli_Brun
  326.   cmp  ax,10h                                    { is it a FLI_COPY chunk? }
  327.   je   Fli_Copy
  328.   jmp  Fli_Loop                                  { This command should not be necessary since the Program should make one - }
  329.                                                  { - of the other jumps }
  330.  
  331. Fli_Color:
  332.   mov  bx,[Word ptr ds:si]                       { number of packets in this chunk (allways 1?) }
  333.   add  si,2                                      { skip the NumberofPackets }
  334.   mov  al,0                                      { start at color 0 }
  335.   xor  cx,cx                                     { reset CX }
  336.  
  337. Color_Loop:
  338.   or   bx,bx                                     { set flags }
  339.   jz   Fli_Loop                                  { Exit if no more packages }
  340.   dec  bx                                        { decrement NumberofPackages For the package to process now }
  341.  
  342.   mov  cl,[Byte ptr ds:si+0]                     { first Byte in packet tells how many colors to skip }
  343.   add  al,cl                                     { add the skiped colors to the start to get the new start }
  344.   mov  dx,$3C8                                   { PEL Address Write Mode Register }
  345.   out  dx,al                                     { tell the VGA card what color we start changing }
  346.  
  347.   inc  dx                                        { at the port abow the PEL_A_W_M_R is the PEL Data Register }
  348.   mov  cl,[Byte ptr ds:si+1]                     { next Byte in packet tells how many colors to change }
  349.   or   cl,cl                                     { set the flags }
  350.   jnz  Jump_Over                                 { if NumberstoChange=0 then NumberstoChange=256 }
  351.   inc  ch                                        { CH=1 and CL=0 => CX=256 }
  352. Jump_Over:
  353.   add  al,cl                                     { update the color to start at }
  354.   mov  di,cx                                     { since each color is made of 3 Bytes (Red, Green & Blue) we have to - }
  355.   shl  cx,1                                      { - multiply CX (the data counter) With 3 }
  356.   add  cx,di                                     { - CX = old_CX shl 1 + old_CX   (the fastest way to multiply With 3) }
  357.   add  si,2                                      { skip the NumberstoSkip and NumberstoChange Bytes }
  358.   rep  outsb                                     { put the color data to the VGA card FAST! }
  359.  
  360.   jmp  Color_Loop                                { finish With this packet - jump back }
  361.  
  362.  
  363. Fli_Lc:
  364.   mov  ax,0A000h
  365.   mov  es,ax                                     { let ES point at the screen segment }
  366.   mov  di,[Word ptr ds:si+0]                     { put LinestoSkip into DI - }
  367.   mov  ax,di                                     { - to get the offset address to this line we have to multiply With 320 - }
  368.   shl  ax,8                                      { - DI = old_DI shl 8 + old_DI shl 6 - }
  369.   shl  di,6                                      { - it is the same as DI = old_DI*256 + old_DI*64 = old_DI*320 - }
  370.   add  di,ax                                     { - but this way is faster than a plain mul }
  371.   mov  bx,[Word ptr ds:si+2]                     { put LinestoChange into BX }
  372.   add  si,4                                      { skip the LinestoSkip and LinestoChange Words }
  373.   xor  cx,cx                                     { reset cx }
  374.  
  375. Line_Loop:
  376.   or   bx,bx                                     { set flags }
  377.   jz  Fli_Loop                                   { Exit if no more lines to change }
  378.   dec  bx
  379.  
  380.   mov  dl,[Byte ptr ds:si]                       { put PacketsInLine into DL }
  381.   inc  si                                        { skip the PacketsInLine Byte }
  382.   push di                                        { save the offset address of this line }
  383.  
  384. Pack_Loop:
  385.   or   dl,dl                                     { set flags }
  386.   jz   Next_Line                                 { Exit if no more packets in this line }
  387.   dec  dl
  388.   mov  cl,[Byte ptr ds:si+0]                     { put BytestoSkip into CL }
  389.   add  di,cx                                     { update the offset address }
  390.   mov  cl,[Byte ptr ds:si+1]                     { put BytesofDatatoCome into CL }
  391.   or   cl,cl                                     { set flags }
  392.   jns  Copy_Bytes                                { no SIGN means that CL number of data is to come - }
  393.                                                  { - else the next data should be put -CL number of times }
  394.   mov  al,[Byte ptr ds:si+2]                     { put the Byte to be Repeated into AL }
  395.   add  si,3                                      { skip the packet }
  396.   neg  cl                                        { Repeat -CL times }
  397.   rep  stosb
  398.   jmp  Pack_Loop                                 { finish With this packet }
  399.  
  400. Copy_Bytes:                                      
  401.   add  si,2                                      { skip the two count Bytes at the start of the packet }
  402.   rep  movsb
  403.   jmp  Pack_Loop                                 { finish With this packet }
  404.  
  405. Next_Line:
  406.   pop  di                                        { restore the old offset address of the current line }
  407.   add  di,320                                    { offset address to the next line }
  408.   jmp  Line_Loop
  409.  
  410.  
  411. Fli_Black:
  412.   mov  ax,0A000h
  413.   mov  es,ax                                     { let ES:DI point to the start of the screen }
  414.   xor  di,di
  415.   mov  cx,32000                                  { number of Words in a screen }
  416.   xor  ax,ax                                     { color 0 is to be put on the screen }
  417.   rep  stosw
  418.   jmp  Fli_Loop                                  { jump back to main loop }
  419.  
  420.  
  421. Fli_Brun:
  422.   mov  ax,0A000h
  423.   mov  es,ax                                     { let ES:DI point at the start of the screen }
  424.   xor  di,di
  425.   mov  bx,200                                    { numbers of lines in a screen }
  426.   xor  cx,cx
  427.  
  428. Line_Loop2:
  429.   mov  dl,[Byte ptr ds:si]                       { put PacketsInLine into DL }
  430.   inc  si                                        { skip the PacketsInLine Byte }
  431.   push di                                        { save the offset address of this line }
  432.  
  433. Pack_Loop2:
  434.   or   dl,dl                                     { set flags }
  435.   jz   Next_Line2                                { Exit if no more packets in this line }
  436.   dec  dl
  437.   mov  cl,[Byte ptr ds:si]                       { put BytesofDatatoCome into CL }
  438.   or   cl,cl                                     { set flags }
  439.   js   Copy_Bytes2                               { SIGN meens that CL number of data is to come - }
  440.                                                  { - else the next data should be put -CL number of times }
  441.   mov  al,[Byte ptr ds:si+1]                     { put the Byte to be Repeated into AL }
  442.   add  si,2                                      { skip the packet }
  443.   rep  stosb
  444.   jmp  Pack_Loop2                                { finish With this packet }
  445.  
  446. Copy_Bytes2:
  447.   inc  si                                        { skip the count Byte at the start of the packet }
  448.   neg  cl                                        { Repeat -CL times }
  449.   rep  movsb
  450.   jmp  Pack_Loop2                                { finish With this packet }
  451.  
  452. Next_Line2:
  453.   pop  di                                        { restore the old offset address of the current line }
  454.   add  di,320                                    { offset address to the next line }
  455.   dec  bx                                        { any more lines to draw? }
  456.   jnz  Line_Loop2
  457.   jmp  Fli_Loop                                  { jump back to main loop }
  458.  
  459.  
  460. Fli_Copy:
  461.   mov  ax,0A000h
  462.   mov  es,ax                                     { let ES:DI point to the start of the screen }
  463.   xor  di,di
  464.   mov  cx,32000                                  { number of Words in a screen }
  465.   rep  movsw
  466.   jmp  Fli_Loop                                  { jump back to main loop }
  467.  
  468.  
  469. Exit:
  470.   sti                                            { enable interrupts }
  471.   pop  es
  472.   pop  ds
  473. end;
  474.  
  475.  
  476.  
  477. begin
  478.   WriteLn;
  479.   WriteLn('.FLI-Player v1.1 by Thaco');
  480.   WriteLn('  (c) EPOS, August 1992');
  481.   WriteLn;
  482.   if ParamCount=0 then                           { if no input parameters then Write the 'usage Text' }
  483.   begin
  484.     WriteLn('USAGE: FLIPLAY <options> <Filename>');
  485.     WriteLn('                   '+#24+'         '+#24);
  486.     WriteLn('                   │         └──  Filename of .FLI File');
  487.     WriteLn('                   └────────────  -d   = Do not use XMS');
  488.     WriteLn('                                  -i   = InFormation about the Program');
  489.     WriteLn('                                  -n   = No checking of MCGA mode support');
  490.     WriteLn('                                  -sNN = Set playspeed to NN video ticks (0-99)');
  491.     WriteLn('                                         ( NN=70 ≈ frame Delay of 1 second )');
  492.     Halt(0);
  493.   end;
  494.  
  495.   For Counter:=1 to ParamCount do                { search through the input parameters For a -Info option }
  496.     if Pos('-I',UpCaseString(ParamStr(Counter)))<>0 then
  497.     begin
  498.       WriteLn('Program inFormation:');
  499.       WriteLn('This Program plays animations (sequences of pictures) made by Programs like',#10#13,
  500.               'Autodesk Animator (so called .FLI-Files). The Program decodes the .FLI File,',#10#13,
  501.               'frame by frame, and Uses the systemclock For mesuring the time-Delay between',#10#13,
  502.               'each frame.');
  503.       WriteLn('Basis For the Program was the FliLib package made by Jim Kent, but since the',#10#13,
  504.               'original source was written in C, and I am not a good C-Writer, I decided',#10#13,
  505.               'to Write my own .FLI-player in Turbo Pascal v6.0.');
  506.       WriteLn('This Program was made by Eirik Milch Pedersen (thaco@solan.Unit.no).');
  507.       WriteLn('Copyright Eirik Pedersens Own SoftwareCompany (EPOS), August 1992');
  508.       WriteLn;
  509.       WriteLn('Autodesk Animator is (c) Autodesk Inc');
  510.       WriteLn('FliLib is (c) Dancing Flame');
  511.       WriteLn('Turbo Pascal is (c) Borland International Inc');
  512.       Halt(0);
  513.     end;
  514.  
  515.   Speed:=-1;
  516.   Counter:=1;
  517.   While (Copy(ParamStr(Counter),1,1)='-') and (ParamCount>=Counter) do { search through the input parameters to assemble them }
  518.   begin
  519.    if Pos('-D',UpCaseString(ParamStr(Counter)))<>0 then  { do not use XMS For storing the File into memory }
  520.      UseXMS:=False
  521.    else
  522.      if Pos('-N',UpCaseString(ParamStr(Counter)))<>0 then  { do not check For a vga card present }
  523.        MCGACheck:=False
  524.      else
  525.        if Pos('-S',UpCaseString(ParamStr(Counter)))<>0 then { speed override has been specified }
  526.        begin
  527.          SpeedString:=Copy(ParamStr(Counter),3,2);  { cut out the NN parameter }
  528.          if not(SpeedString[1] in ['0'..'9']) or    { check if the NN parameter is legal }
  529.             (not(SpeedString[2] in ['0'..'9',' ']) and (Length(SpeedString)=2)) then
  530.          begin
  531.            WriteLn('ERRor! Can not parse speed ''',SpeedString,'''.');
  532.            Halt(0);
  533.          end;
  534.          Speed:=Byte(SpeedString[1])-48;  { take the first number, in ASCII, and convert it to a standard number }
  535.          if Length(SpeedString)=2 then    { if there is two numbers then multiply the first With 10 and add the next }
  536.            Speed:=Speed*10+Byte(SpeedString[2])-48;
  537.          Speed:=Speed*CLOCK_SCALE;        { convert the speed to number of clock tics }
  538.        end;
  539.    Inc(Counter);
  540.   end;
  541.  
  542.   if ParamCount<Counter then
  543.   begin
  544.     WriteLn('ERRor! No Filename specified.');
  545.     Halt(0);
  546.   end;
  547.  
  548.   FileName:=UpCaseString(ParamStr(Counter));
  549.   if Pos('.',FileName)=0 then  { find out if there exist a . in the Filename }
  550.     FileName:=FileName+'.FLI'; { if not then add the .FLI extension on the Filename }
  551.  
  552.   if MaxAvail<BUFFERSIZE then   { check if there is enough memory to the frame buffer }
  553.   begin
  554.     WriteLn('ERRor! Can not allocate enough memory to a frame buffer.');
  555.     Halt(0);
  556.   end;
  557.  
  558.   GetMem(Buffer,BUFFERSIZE);
  559.   Assign(InputFile,FileName);
  560.   Reset(InputFile,1);
  561.   if Ioresult<>0 then  { has an error occured during opening the File? }
  562.   begin
  563.     WriteLn('ERRor! Can not open File ''',FileName,'''.');
  564.     Halt(0);
  565.   end;
  566.  
  567.   if not(MCGACheck) or ModeSupport(MCGA) then
  568.     InitMode(MCGA)
  569.   else
  570.   begin
  571.     WriteLn('ERRor! Video mode 013h - 320x200x256 colors - is not supported.');
  572.     Halt(0);
  573.   end;
  574.  
  575.   BlockRead(InputFile,Header,128);  { read the .FLI main header }
  576.  
  577.   if not((Header[4]=$11) and (Header[5]=$AF)) then  { check if the File has got the magic number }
  578.   begin
  579.     InitMode(CO80);
  580.     WriteLn('ERRor! File ''',FileName,''' is of a wrong File Type.');
  581.     Halt(0);
  582.   end;
  583.  
  584.   if NoXMS then  { if no XMS driver present then do not use XMS }
  585.     UseXMS:=False;
  586.  
  587.   if UseXMS then
  588.   begin
  589.     FileSize:=Header[0]+256*(LongInt(Header[1])+256*(LongInt(Header[2])+256*LongInt(Header[3])));
  590.     if XMSMaxAvail<=(FileSize+1023) SHR 10 then  { is there enough XMS (rounded up to Nearest KB) availible? }
  591.     begin
  592.       WriteLn('ERRor! not enough XMS For the File');
  593.       Halt(0);
  594.     end
  595.     else
  596.     begin
  597.       Seek(InputFile,0);  { skip back to start of .FLI-File to put it all into XMS }
  598.       BufferHandle:=XMSGetMem((FileSize+1023) SHR 10);  { allocate XMS For the whole .FLI File }
  599.       FileCounter:=0;
  600.       Repeat
  601.         BlockRead(InputFile,Buffer^,BUFFERSIZE,BytesRead);  { read a part from the .FLI File }
  602.         if BytesRead MOD 2=1 then  { since BUFFERSIZE shoud be an even number, the only time this triggers is the last part }
  603.           Inc(BytesRead);          { must be done because the XMS routine demands an even number of Bytes to be moved }
  604.         if BytesRead<>0 then
  605.         begin
  606.           With XMSRecord do  { put data into the XMSRecord }
  607.           begin
  608.             BytestoMoveLo      :=BytesRead;
  609.             BytestoMoveHi      :=0;
  610.             SourceHandle       :=0;
  611.             SourceoffsetLo     :=ofs(Buffer^);
  612.             SourceoffsetHi     :=Seg(Buffer^);
  613.             DestinationHandle  :=BufferHandle;
  614.             DestinationoffsetLo:=FileCounter MOD 65536;
  615.             DestinationoffsetHi:=FileCounter div 65536;
  616.           end;
  617.           XMSMove(XMSRecord);   { move Bytes to XMS }
  618.           if XMSError<>0 then   { have any XMS errors occured? }
  619.             ExitDuetoXMSError;
  620.           Inc(FileCounter,BytesRead);  { update the offset into XMS where to put the next Bytes }
  621.         end;
  622.       Until BytesRead<>BUFFERSIZE;  { Repeat Until Bytes read <> Bytes tried to read => end of File }
  623.     end;
  624.     FileCounter:=128;  { we continue (after reading the .FLI File into XMS) right after the .FLI main header }
  625.   end;
  626.  
  627.   Frames:=Header[6]+Header[7]*256;  { get the number of frames from the .FLI-header }
  628.   if Speed=-1 then                  { if speed is not set by a speed override then get it from the .FLI-header }
  629.     Speed:=(Header[16]+Integer(Header[17])*256)*CLOCK_SCALE;
  630.   InitClock;  { initialize the System Clock }
  631.   OldKey:=PorT[$60];  { get the current value from the keyboard }
  632.   Key:=OldKey;        { and set the 'current key' Variable to the same value }
  633.  
  634.   GetBlock(Header,16);  { read the first frame-header }
  635.   FrameSize:=Header[0]+256*(LongInt(Header[1])+256*(LongInt(Header[2])+256*LongInt(Header[3])))-16;  { calculate framesize }
  636.   SecondPos:=128+16+FrameSize;  { calculate what position to skip to when the .FLI is finished and is going to start again - }
  637.                                 { the position = .FLI-header + first_frame-header + first_framesize }
  638.   Chunks:=Header[6]+Header[7]*256;  { calculate number of chunks in frame }
  639.   GetBlock(Buffer^,FrameSize);  { read the frame into the framebuffer }
  640.   TreatFrame(Buffer,Chunks);  { treat the first frame }
  641.  
  642.   TimeCounter:=GetClock;  { get the current time }
  643.  
  644.   {
  645.     The first frame must be handeled separatly from the rest. This is because the rest of the frames are updates/changes of the
  646.     first frame.
  647.     At the end of the .FLI-File there is one extra frame who handles the changes from the last frame to the first frame.
  648.   }
  649.  
  650.   Repeat
  651.     FrameNumber:=1;  { we start at the first frame (after the initial frame) }
  652.     Repeat
  653.       GetBlock(Header,16);  { read frame-header }
  654.       FrameSize:=Header[0]+256*(LongInt(Header[1])+256*(LongInt(Header[2])+256*LongInt(Header[3])))-16;  { size of frame }
  655.       if FrameSize<>0 then  { sometimes there are no changes from one frame to the next (used For extra Delays). In such - }
  656.                             { - Cases the size of the frame is 0 and we don't have to process them }
  657.       begin
  658.         Chunks:=Header[6]+Header[7]*256;  { calculate number of chunks in the frame }
  659.         GetBlock(Buffer^,FrameSize);  { read the frame into the framebuffer }
  660.         TreatFrame(Buffer,Chunks);  { treat the frame }
  661.       end;
  662.  
  663.       NextTime:=TimeCounter+Speed;   { calculate the Delay to the next frame }
  664.       While TimeCounter<NextTime do  { wait For this long }
  665.         TimeCounter:=GetClock;
  666.  
  667.       if PorT[$64]=KEYBOARD then   { check if the value at the keyboard port is caused by a key pressed }
  668.         Key:=PorT[$60];            { get the current value from the keyboard }
  669.       Inc(FrameNumber);  { one frame finished, over to the next one }
  670.     Until (FrameNumber>Frames) or (Key<>OldKey);  { Repeated Until we come to the last frame or a key is pressed }
  671.  
  672.     if UseXMS then
  673.       FileCounter:=SecondPos
  674.     else
  675.       Seek(InputFile,SecondPos);  { set current position in the File to the second frame }
  676.  
  677.   Until Key<>OldKey;  { Exit the loop if a key has been pressed }
  678.  
  679.   InitMode(CO80);  { get back to Text mode }
  680.  
  681.   Close(InputFile);            { be a kind boy and close the File beFore we end the Program }
  682.   FreeMem(Buffer,BUFFERSIZE);  { and free the framebuffer }
  683.  
  684.   if UseXMS then
  685.     XMSFreeMem(BufferHandle);
  686. END.